<script setup lang="ts" generic="T = boolean | string | number">
import {nextTick, onMounted} from "vue"
import type {SwitchProp} from "./type/SwitchProp.ts"
import {useSwitch} from "./composables/useSwitch"
import type {SwitchEmit} from "@/components/switch/type/SwitchEmit.ts";

const $emits = defineEmits<SwitchEmit<T>>()
const $props = withDefaults(defineProps<SwitchProp<T>>(), {
  labelWidth: 80,
  activeColor: "#409EFF",
  inactiveColor: "#DBDBDB",
  loading: false,
  disabled: false,
  width: 50,
  thumbSize: 16,
  fontSize: 14
})

const {width, isActive, switchChange, autoWidth, lightActiveColor, lightInactiveColor} = useSwitch($props, $emits)

onMounted(() => {
  nextTick(autoWidth)
})
</script>

<template>
  <div class="switch-container">
    <!-- switch的标题 -->
    <span v-if="label" class="switch-label">{{ label }}</span>
    <div class="switch-border">
      <!-- switch主体 -->
      <div class="switch-body" :class="{ active: isActive }" @click="switchChange">
        <!-- switch激活和失活的背景色 -->
        <div class="background">
          <!-- switch激活时 -->
          <div class="bg bg-active">
            <span ref="activeRef" class="active-text">{{ activeText }}</span>
          </div>
          <!-- switch失活时 -->
          <div class="bg bg-inactive">
            <span ref="inactiveRef" class="inactive-text">{{ inactiveText }}</span>
          </div>
        </div>

        <!-- switch的滑块 -->
        <div class="thumb" :class="{ loading: loading }">
          <slot name="icon"/>
          <!-- 滑块的loading状态 -->
          <span v-if="loading" class="loading-spinner"/>
        </div>

        <!-- 遮罩层：loading 时显示，阻止点击事件 -->
        <div v-if="loading || disabled" :class="{'switch-mask': true, disabled: disabled}" @click.stop/>
      </div>
    </div>
  </div>
</template>

<style scoped>
.switch-container {
  line-height: 1;
  display: inline-flex;
  align-items: center;
  margin: 4px;
}

.switch-label {
  width: v-bind(labelWidth+ 'px');
  font-size: v-bind(fontSize+ "px");
  line-height: 1;
  user-select: none;
  text-align: right;
  padding: 2px 14px 2px 4px;
}

.switch-border {
  border-radius: 15px;
  width: calc(v-bind(width+ "px") + 4px);
  height: calc(v-bind(thumbSize+ "px") + 8px);
  background-color: transparent;
  transition: background-color .2s;
}

.switch-body {
  /* 宽度随内容撑开 */
  display: inline-block;
  /* 最小宽度兜底 */
  width: v-bind(width+ "px");
  height: calc(v-bind(thumbSize+ "px") + 4px);
  border-radius: 15px;
  position: relative;
  overflow: hidden;
  cursor: pointer;
  user-select: none;

  margin: 2px;
}

/* 背景容器：放两个颜色块 */
.background {
  position: absolute;
  /* top/right/bottom/left = 0 */
  inset: 0;
  display: flex;
  /* 整个背景块是其父容器的两倍宽度，以便放下off和on两个子背景块 */
  width: 200%;
  transform: translateX(-50%);
  transition: transform .3s ease;
}

/* 每个颜色块占一半 */
.bg {
  flex: 1 0 50%;
  display: flex;
  justify-content: center;
  align-items: center;
  color: #fff;
}

.bg.bg-active {
  background: v-bind(activeColor);
  padding-right: v-bind(thumbSize+ 'px');
}

.bg.bg-inactive {
  background: v-bind(inactiveColor);
  padding-left: v-bind(thumbSize+ 'px');
}

.inactive-text {
  font-size: v-bind(fontSize+ "px");
}

.active-text {
  font-size: v-bind(fontSize+ "px");
}

/* 滑块 */
.thumb {
  position: absolute;
  top: 2px;
  left: 2px;
  width: v-bind(thumbSize+ "px");
  height: v-bind(thumbSize+ "px");
  border-radius: 50%;
  background: #fff;
  transition: left .3s ease; /* 只改 left，就能响应任何宽度 */
  z-index: 1;
  overflow: hidden;
}

.thumb.loading {
  animation: spin 0.8s linear infinite;
}

/* switch激活时，background回到初始位置 */
.switch-body.active .background {
  transform: translateX(0);
}

/* switch激活时，滑块向右边平移 */
.switch-body.active .thumb {
  left: calc(100% - v-bind(thumbSize+ "px") - 2px);
}

/* switch边框 */
.switch-border:has(.switch-body:active) {
  background-color: v-bind(lightActiveColor);
}

.switch-border:has(.switch-body:not(.active):active) {
  background-color: v-bind(lightInactiveColor);
}

/* 滑块的loading状态 */
.switch-mask {
  position: absolute;
  inset: 0;
  background: transparent;
  cursor: wait; /* 显示沙漏 */
  z-index: 10; /* 保证在最上面 */
  border-radius: 15px; /* 保证圆角跟随switch */
}

.switch-mask.disable {
  cursor: not-allowed;
}

.thumb.loading {
  box-shadow: none;
  pointer-events: none;
  display: flex;
  align-items: center;
  justify-content: center;
}

.loading-spinner {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);

  width: 80%;
  height: 80%;

  border: 1px solid v-bind(activeColor);
  border-top-color: transparent;
  border-radius: 50%;

  z-index: 2;
}

@keyframes spin {
  to {
    transform: rotate(360deg);
  }
}

</style>